<template>
  <el-button type="primary" @click="show = !show">点我</el-button>
  <div class="test-vif" v-if="show" style="width: 100px; height: 100px; background: pink">123</div>
  <div class="test-show" v-show="show" style="width: 100px; height: 100px; background: yellow">
    456
  </div>
  <van-button type="primary">主要按钮</van-button>
  <div class="upload-container">
    <!-- 文件选择区域 -->
    <div class="upload-area" @click="triggerFileInput" @drop.prevent="handleDrop" @dragover.prevent>
      <input
        type="file"
        ref="fileInput"
        multiple
        @change="handleFileChange"
        style="display: none"
      />
      <div class="upload-content">
        <el-icon class="upload-icon"><Upload /></el-icon>
        <div class="upload-text">
          <p>点击或拖拽文件到此处上传</p>
          <p class="upload-tip">支持大文件上传，单个文件最大支持2GB</p>
        </div>
      </div>
    </div>

    <!-- 上传列表 -->
    <div class="upload-list" v-if="uploadList.length > 0">
      <div v-for="(file, index) in uploadList" :key="index" class="upload-item">
        <div class="file-info">
          <el-icon class="file-icon"><Document /></el-icon>
          <span class="file-name">{{ file.name }}</span>
          <span class="file-size">{{ formatFileSize(file.size) }}</span>
        </div>

        <!-- 上传进度 -->
        <div class="upload-progress">
          <el-progress
            :percentage="file.progress"
            :status="file.status === 'error' ? 'exception' : ''"
          />
          <div class="upload-status">
            <span v-if="file.status === 'uploading'">上传中...</span>
            <span v-else-if="file.status === 'success'">上传成功</span>
            <span v-else-if="file.status === 'error'">上传失败</span>
            <span v-else-if="file.status === 'paused'">已暂停</span>
          </div>
        </div>

        <!-- 操作按钮 -->
        <div class="upload-actions">
          <el-button
            v-if="file.status === 'uploading'"
            type="primary"
            size="small"
            @click="pauseUpload(index)"
          >
            暂停
          </el-button>
          <el-button
            v-if="file.status === 'paused'"
            type="success"
            size="small"
            @click="resumeUpload(index)"
          >
            继续
          </el-button>
          <el-button
            v-if="file.status === 'error'"
            type="warning"
            size="small"
            @click="retryUpload(index)"
          >
            重试
          </el-button>
          <el-button type="danger" size="small" @click="removeFile(index)"> 删除 </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload, Document } from '@element-plus/icons-vue'
import SparkMD5 from 'spark-md5'

const show = ref(false)

// 文件分片大小：500MB
const CHUNK_SIZE = 500 * 1024 * 1024
// 允许的文件类型
const ALLOWED_TYPES = [
  'application/pdf',
  'image/jpeg',
  'image/png',
  'image/gif',
  'application/ofd',
  // 可以添加更多文件类型
]

// 文件输入框引用
const fileInput = ref<HTMLInputElement | null>(null)

// 上传列表
interface UploadFile {
  file: File
  name: string
  size: number
  progress: number
  status: 'waiting' | 'uploading' | 'paused' | 'success' | 'error'
  chunks: Blob[]
  uploadedChunks: number[]
  fileHash?: string
}

const uploadList = ref<UploadFile[]>([])

// 触发文件选择
const triggerFileInput = () => {
  fileInput.value?.click()
}

// 处理文件选择
const handleFileChange = (event: Event) => {
  const files = (event.target as HTMLInputElement).files
  if (files) {
    handleFiles(Array.from(files))
  }
}

// 处理拖拽文件
const handleDrop = (event: DragEvent) => {
  const files = event.dataTransfer?.files
  if (files) {
    handleFiles(Array.from(files))
  }
}

// 处理文件列表
const handleFiles = async (files: File[]) => {
  for (const file of files) {
    // 检查文件类型
    if (!ALLOWED_TYPES.includes(file.type)) {
      ElMessage.error(`不支持的文件类型: ${file.type}`)
      continue
    }

    // 检查文件大小
    if (file.size > 2 * 1024 * 1024 * 1024) {
      // 2GB
      ElMessage.error('文件大小不能超过2GB')
      continue
    }

    // 计算文件hash
    const fileHash = await calculateFileHash(file)

    // 创建上传文件对象
    const uploadFile: UploadFile = {
      file,
      name: file.name,
      size: file.size,
      progress: 0,
      status: 'waiting',
      chunks: [],
      uploadedChunks: [],
      fileHash,
    }

    // 分片
    uploadFile.chunks = createFileChunks(file)
    uploadList.value.push(uploadFile)

    // 开始上传
    startUpload(uploadList.value.length - 1)
  }
}

// 计算文件hash
const calculateFileHash = (file: File): Promise<string> => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.readAsArrayBuffer(file)
    reader.onload = (e) => {
      const buffer = e.target?.result
      const spark = new SparkMD5.ArrayBuffer()
      spark.append(buffer as ArrayBuffer)
      const hash = spark.end()
      resolve(hash)
    }
  })
}

// 创建文件分片
const createFileChunks = (file: File): Blob[] => {
  const chunks: Blob[] = []
  let cur = 0
  while (cur < file.size) {
    chunks.push(file.slice(cur, cur + CHUNK_SIZE))
    cur += CHUNK_SIZE
  }
  return chunks
}

// 开始上传
const startUpload = async (index: number) => {
  const uploadFile = uploadList.value[index]
  uploadFile.status = 'uploading'
  if (!uploadFile) return

  // 检查已上传的分片
  const uploadedChunks = await checkUploadedChunks(uploadFile.fileHash!)
  uploadFile.uploadedChunks = uploadedChunks

  // 上传未完成的分片
  for (let i = 0; i < uploadFile.chunks.length; i++) {
    if (uploadFile.uploadedChunks.includes(i)) {
      continue
    }

    if (uploadFile.status === 'paused') {
      break
    }

    try {
      await uploadChunk(uploadFile, i)
      uploadFile.uploadedChunks.push(i)
      uploadFile.progress = Math.floor(
        (uploadFile.uploadedChunks.length / uploadFile.chunks.length) * 100,
      )
    } catch (error) {
      uploadFile.status = 'error'
      ElMessage.error(`分片 ${i + 1} 上传失败`)
      return
    }
  }

  // 所有分片上传完成，合并文件
  if (uploadFile.uploadedChunks.length === uploadFile.chunks.length) {
    try {
      await mergeChunks(uploadFile)
      uploadFile.status = 'success'
      ElMessage.success('文件上传成功')
    } catch (error) {
      uploadFile.status = 'error'
      ElMessage.error('文件合并失败')
    }
  }
}

// 检查已上传的分片
const checkUploadedChunks = async (fileHash: string): Promise<number[]> => {
  try {
    const response = await fetch(`/api/check-chunks?fileHash=${fileHash}`)
    const data = await response.json()
    return data.uploadedChunks || []
  } catch (error) {
    console.error('检查分片失败:', error)
    return []
  }
}

// 上传分片
const uploadChunk = async (uploadFile: UploadFile, chunkIndex: number) => {
  const formData = new FormData()
  formData.append('chunk', uploadFile.chunks[chunkIndex])
  formData.append('hash', `${uploadFile.fileHash}-${chunkIndex}`)
  formData.append('fileHash', uploadFile.fileHash!)
  formData.append('chunkIndex', chunkIndex.toString())

  try {
    const response = await fetch('/api/upload-chunk', {
      method: 'POST',
      body: formData,
    })
    if (!response.ok) {
      throw new Error('上传失败')
    }
  } catch (error) {
    throw error
  }
}

// 合并分片
const mergeChunks = async (uploadFile: UploadFile) => {
  try {
    const response = await fetch('/api/merge-chunks', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        fileHash: uploadFile.fileHash,
        fileName: uploadFile.name,
        chunkCount: uploadFile.chunks.length,
      }),
    })
    if (!response.ok) {
      throw new Error('合并失败')
    }
  } catch (error) {
    throw error
  }
}

// 暂停上传
const pauseUpload = (index: number) => {
  const uploadFile = uploadList.value[index]
  if (uploadFile) {
    uploadFile.status = 'paused'
  }
}

// 继续上传
const resumeUpload = (index: number) => {
  startUpload(index)
}

// 重试上传
const retryUpload = (index: number) => {
  const uploadFile = uploadList.value[index]
  if (uploadFile) {
    uploadFile.status = 'uploading'
    uploadFile.progress = 0
    uploadFile.uploadedChunks = []
    startUpload(index)
  }
}

// 移除文件
const removeFile = (index: number) => {
  uploadList.value.splice(index, 1)
}

// 格式化文件大小
const formatFileSize = (size: number): string => {
  if (size < 1024) {
    return size + 'B'
  } else if (size < 1024 * 1024) {
    return (size / 1024).toFixed(2) + 'KB'
  } else if (size < 1024 * 1024 * 1024) {
    return (size / (1024 * 1024)).toFixed(2) + 'MB'
  } else {
    return (size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'
  }
}
</script>

<style scoped lang="scss">
.upload-container {
  padding: 20px;

  .upload-area {
    border: 2px dashed #dcdfe6;
    border-radius: 6px;
    padding: 40px;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.3s;

    &:hover {
      border-color: #409eff;
    }

    .upload-content {
      .upload-icon {
        font-size: 48px;
        color: #909399;
      }

      .upload-text {
        margin-top: 10px;
        color: #606266;

        .upload-tip {
          font-size: 12px;
          color: #909399;
          margin-top: 5px;
        }
      }
    }
  }

  .upload-list {
    margin-top: 20px;

    .upload-item {
      padding: 10px;
      border: 1px solid #ebeef5;
      border-radius: 4px;
      margin-bottom: 10px;

      .file-info {
        display: flex;
        align-items: center;
        margin-bottom: 10px;

        .file-icon {
          font-size: 20px;
          color: #909399;
          margin-right: 10px;
        }

        .file-name {
          flex: 1;
          margin-right: 10px;
        }

        .file-size {
          color: #909399;
        }
      }

      .upload-progress {
        margin-bottom: 10px;

        .upload-status {
          font-size: 12px;
          color: #909399;
          margin-top: 5px;
        }
      }

      .upload-actions {
        display: flex;
        justify-content: flex-end;
        gap: 10px;
      }
    }
  }
}
</style>
